#include "Cube.h"
#include "VertexTypes.h"

Cube::Cube(ID3D10Device* pDevice)
{
	pEffect = NULL;
	pTechnique = NULL;
	pVertexLayout = NULL;
	pVertexBuffer = NULL;
	pIndexBuffer = NULL;

	D3DXMatrixIdentity(&World);

	this->pDevice = pDevice;
}

Cube::~Cube(void)
{
	if (pVertexBuffer != NULL) pVertexBuffer->Release();
	if (pIndexBuffer != NULL) pIndexBuffer->Release();
	if (pVertexLayout != NULL) pVertexLayout->Release();
	if (pEffect != NULL) pEffect->Release();
}

HRESULT Cube::Initialize()
{
	HRESULT hr;

	hr = InitializeEffect();
	if (FAILED(hr)) return hr;

	hr = InitializeVertexLayout();
	if (FAILED(hr)) return hr;

	hr = InitializeVertexBuffer();
	if (FAILED(hr)) return hr;

	hr = InitializeIndexBuffer();
	if (FAILED(hr)) return hr;
	
	return S_OK;
}

HRESULT Cube::InitializeVertexLayout()
{
	HRESULT hr;

	D3D10_PASS_DESC PassDesc;
	pTechnique->GetPassByIndex(0)->GetDesc(&PassDesc);
	hr = pDevice->CreateInputLayout(PositionColorVertexLayout, PositionColorVertexNumElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &pVertexLayout);
	if (FAILED(hr)) return hr;

	return S_OK;
}

HRESULT Cube::InitializeVertexBuffer()
{
	HRESULT hr;

	PositionColorVertex vertices[] =
	{
        { D3DXVECTOR3( -1.0f,  1.0f, -1.0f ), D3DXVECTOR4( 0.0f, 0.0f, 1.0f, 1.0f ) },
        { D3DXVECTOR3(  1.0f,  1.0f, -1.0f ), D3DXVECTOR4( 0.0f, 1.0f, 0.0f, 1.0f ) },
        { D3DXVECTOR3(  1.0f,  1.0f,  1.0f ), D3DXVECTOR4( 0.0f, 1.0f, 1.0f, 1.0f ) },
        { D3DXVECTOR3( -1.0f,  1.0f,  1.0f ), D3DXVECTOR4( 1.0f, 0.0f, 0.0f, 1.0f ) },
        { D3DXVECTOR3( -1.0f, -1.0f, -1.0f ), D3DXVECTOR4( 1.0f, 0.0f, 1.0f, 1.0f ) },
        { D3DXVECTOR3(  1.0f, -1.0f, -1.0f ), D3DXVECTOR4( 1.0f, 1.0f, 0.0f, 1.0f ) },
        { D3DXVECTOR3(  1.0f, -1.0f,  1.0f ), D3DXVECTOR4( 1.0f, 1.0f, 1.0f, 1.0f ) },
        { D3DXVECTOR3( -1.0f, -1.0f,  1.0f ), D3DXVECTOR4( 0.0f, 0.0f, 0.0f, 1.0f ) },
	};
	
	D3D10_BUFFER_DESC bd;
	bd.Usage = D3D10_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(PositionColorVertex)*8;
	bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;

	D3D10_SUBRESOURCE_DATA InitData;
	InitData.pSysMem = vertices;

	hr = pDevice->CreateBuffer(&bd, &InitData, &pVertexBuffer);
	if (FAILED(hr)) return hr;

	this->stride = sizeof(PositionColorVertex);
	this->offset = 0;
	
	return S_OK;
}

HRESULT Cube::InitializeIndexBuffer()
{
	HRESULT hr;
    DWORD indices[] =
    {
        3,1,0,
        2,1,3,

        0,5,4,
        1,5,0,

        3,4,7,
        0,4,3,

        1,6,5,
        2,6,1,

        2,7,6,
        3,7,2,

        6,4,5,
        7,4,6,
    };

	D3D10_BUFFER_DESC bd;
	bd.Usage = D3D10_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(DWORD) * 36;
	bd.BindFlags = D3D10_BIND_INDEX_BUFFER;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;

	D3D10_SUBRESOURCE_DATA InitData;
	InitData.pSysMem = indices;

	hr = pDevice->CreateBuffer(&bd, &InitData, &pIndexBuffer);
	if (FAILED(hr)) return hr;

	return S_OK;
}

HRESULT Cube::InitializeEffect()
{
	HRESULT hr;

	hr = D3DX10CreateEffectFromFile(L"Cube.fx", NULL, NULL, "fx_4_0", D3D10_SHADER_ENABLE_STRICTNESS | D3D10_SHADER_DEBUG, 0, pDevice, NULL, NULL, &pEffect, NULL, NULL);
	if (FAILED(hr)) return hr;

	pTechnique = pEffect->GetTechniqueByName("Render");

	pWorldVariable = pEffect->GetVariableByName("World")->AsMatrix();
	pViewProjVariable = pEffect->GetVariableByName("ViewProj")->AsMatrix();

	return S_OK;
}

void Cube::Update(float timeElapsed)
{
	D3DXMatrixRotationY(&World, timeElapsed);
}

void Cube::Render(D3DXMATRIX viewProj)
{
	pDevice->IASetInputLayout(pVertexLayout);
	pDevice->IASetVertexBuffers(0, 1, &pVertexBuffer, &stride, &offset);
	pDevice->IASetIndexBuffer(pIndexBuffer, DXGI_FORMAT_R32_UINT, 0);
	pDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	pWorldVariable->SetMatrix((float*)&World);
	pViewProjVariable->SetMatrix((float*)viewProj);

	D3D10_TECHNIQUE_DESC techDesc;
	pTechnique->GetDesc(&techDesc);
	for (UINT p = 0; p < techDesc.Passes; ++p)
	{
		pTechnique->GetPassByIndex(p)->Apply(0);
		pDevice->DrawIndexed(36, 0, 0);
	}
}